import json
import RUN1logic


class Logic:
    def __init__(
            self,
            m_client,
            threshold_f,
            threshold_c,
            card_limit,
            redis_client,
            stranger_limit,
            server_port
    ):
        self.threshold_f = float(threshold_f)
        self.threshold_c = float(threshold_c)
        # 初始化mongo
        self.m_client = m_client

        self.config_D = self.m_client.config_D
        self.config_J = self.m_client.config_J
        self.config_A = self.m_client.config_A

        self.ovo_ip = self.config_D.get("ovo_ip")
        self.ovo_port = self.config_D.get("ovo_port")
        self.ovo_whether = self.config_D.get("whether_do")

        self.box_ip_D = self.m_client.box_ip_D
        self.box_ip_J = self.m_client.box_ip_J
        self.box_ip_A = self.m_client.box_ip_A

        self.func_client_D = self.m_client.func_client_D
        self.func_client_J = self.m_client.func_client_J
        self.func_client_A = self.m_client.func_client_A
        # 端口号
        self.server_port = server_port

        # 操作 redis
        self.redis_client = redis_client
        # topk
        self.card_limit = card_limit
        self.stranger_limit = stranger_limit

    # 删除人像库接口--静态库 J
    def delete_card(self, face_id):
        face_data = self.redis_client.get_specific_data(face_id)
        try:
            hezi_face_id = int(face_data.get('hezi_guidang_face_id'))
        except:
            return None

        res = self.func_client_J.delete_face(repo_id=int(face_data.get('hezi_guidang_repo_id')), face_id=hezi_face_id)
        # 修改redis 一个表  Mongo 四个表 + acvs表
        self.redis_client.del_card_redis(face_id)
        # 获取card_acvs
        acvs_list = self.redis_client.get_card_acvs(face_id)

        self.m_client.del_card_mongo(face_id, acvs_list)

        return res

    def saving_logic(self, uri, camera_id, face_id: str, face_b64: str, timestamp, feature: str = None):
        face_feature = None
        # 查看id是否存在
        if self.redis_client.exists_id(face_id) > 0:
            # 判断是否为同一个  hezi_ip
            face_img = self.redis_client.get_specific_data(face_id)
            if face_img['hezi_guidang_ip'] == self.box_ip_D:
                raise Exception("Face id existed.")

        # 获取当前repo id
        repo_id, repo_id_key = self.m_client.get_current_use_repo('D')
        hezi_face_id = self.m_client.get_hezi_face_id()

        # 上传至人像库 (插图片)
        if feature is None:
            ins_result = self.func_client_D.insert_image(
                hezi_face_id=hezi_face_id,
                repo_id=repo_id,
                image=face_b64,
                face_id=face_id
            )
            face_feature = self.get_face_feature(fun_client=self.func_client_D, repo_id=repo_id,
                                                 hezi_face_id=hezi_face_id)
        else:
            face_feature = feature
            ins_result = self.func_client_D.insert_feature(
                hezi_face_id=hezi_face_id,
                repo_id=repo_id,
                feature=feature,
                face_id=face_id
            )
        print("Insert result:", ins_result)
        # 无法解析人脸
        if ins_result.get("message") != "success":
            data_dic = {
                "hezi_guidang_repo_id": "%s" % repo_id,
                "face_id": face_id,
                "hezi_guidang_face_id": hezi_face_id,
                "timestamp": int(timestamp),
                "hezi_guidang_ip": self.box_ip_D
            }
            self.m_client.insert_fail_img(data_dic)
            raise Exception(ins_result.get("message"))

        # 增值
        self.m_client.inc_count(repo_id_key, 'D')
        # mongo 获取人像库id
        repos_d = [self.config_D.get('ID1'), self.config_D.get('ID2'), self.config_D.get('ID3')]
        repos_j = [self.config_J.get('ID1'), self.config_J.get('ID2'), self.config_J.get('ID3')]
        repos_a = [self.config_A.get('ID1'), self.config_A.get('ID2'), self.config_A.get('ID3')]

        # 证件照库ovn
        # card_ovn_data = self.card_ovn([2], face_b64, self.card_limit)
        card_ovn_data = self.card_ovn(repos_j, face_feature)

        # 路人库ovn
        # stranger_ovn_data = self.stranger_ovn(face_id, repos, face_b64, self.stranger_limit)
        stranger_ovn_data = self.stranger_ovn(face_id, repos_d, face_feature)

        # 档案库ovn
        acvs_ovn_data = self.acvs_ovn(face_id, repos_a, face_feature)

        # 合并路人和档案ovn
        for acvs_dic in acvs_ovn_data:
            if acvs_dic not in stranger_ovn_data:
                stranger_ovn_data.append(acvs_dic)

        # 人脸数据
        face_image_data = {
            "_id": str(face_id),
            "face_image_id": str(face_id),
            "hezi_guidang_ip": self.box_ip_D,
            "timestamp": int(timestamp),
            "face_image_uri": str(uri),
            "camera_id": str(camera_id),
            'picture_uri': str(uri),
            "ovn_f": feature if feature else face_feature,
            "face_base64": face_b64,
            "hezi_guidang_face_id": hezi_face_id,
            "hezi_guidang_repo_id": repo_id
        }

        # 贺昌浩处理逻辑
        RUN1logic.logic(face_image_data, stranger_ovn_data, card_ovn_data, self.ovo_ip, self.ovo_port, self.ovo_whether)
        return True

    def get_face_feature(self, fun_client, repo_id, hezi_face_id):
        face_result = fun_client.get_face_one(repo_id, hezi_face_id)
        if face_result.get("status") == 200:
            feature = face_result.get("message")
            return feature
        else:
            return ""

    # 证件ovn
    def card_ovn(self, repo_id: list, face_b64):
        # ovn_data = func.one_than_n_(
        #     ip=self.box_ip,
        #     port=self.box_port,
        #     image=face_b64,
        #     threshold=self.threshold_c,
        #     repositories=repo_id,
        #     topk=limit
        # ).get("message")
        if self.box_ip_J == "0.0.0.0":
            return []

        ovn_data = self.func_client_J.one_than_n_feature(
            feature=face_b64,
            threshold=self.threshold_c,
            repositories=repo_id,
            topk=self.card_limit
        ).get("message")

        # print("证件库 OvN:", ovn_data)
        # 证件ovn列表
        card_face_info = []
        for res in ovn_data.get("retrieval_results"):
            # 比中证件
            for face in res.get("similar_faces"):
                # hit_face_id = face.get("id")
                hit_face_id = json.loads(face.get("extra_meta"))["face_id"]
                similarity = face.get("similarity")
                # db15查询
                try:
                    specific_data = self.redis_client.get_specific_data(hit_face_id)

                    single_card_data = {'face_image_id': str(specific_data.get("face_image_id")),
                                        'repository_id': res.get('repository_id'),
                                        'similarity': similarity,
                                        'face_image_uri': specific_data.get("face_image_uri"),
                                        'picture_uri': specific_data.get("picture_uri"),
                                        'name': specific_data.get("name"),
                                        'person_id': specific_data.get("person_id"),
                                        'timestamp': int(specific_data.get("timestamp")),
                                        'hezi_guidang_ip': specific_data.get("hezi_guidang_ip"),
                                        'ovn_f': specific_data.get("ovn_f")
                                        }
                    # 筛选重复
                    card_face_info.append(single_card_data)
                except Exception as e:
                    continue
        return card_face_info

    # 路人ovn
    def stranger_ovn(self, face_id, repo_id, face_b64):
        # ovn_data = func.one_than_n(
        #     ip=self.box_ip,
        #     port=self.box_port,
        #     image=face_b64,
        #     threshold=self.threshold_f,
        #     repositories=repo_id,
        #     topk=limit
        # ).get("message")
        ovn_data = self.func_client_D.one_than_n_feature(
            feature=face_b64,
            threshold=self.threshold_f,
            repositories=repo_id,
            topk=self.stranger_limit
        ).get("message")

        # print("路人库 OVN:", ovn_data)
        # 路人ovn列表
        stranger_list = []
        for res in ovn_data.get("retrieval_results"):
            # 路人
            for face in res.get("similar_faces"):
                # hit_face_id = face.get("id")
                hit_face_id = json.loads(face.get("extra_meta"))["face_id"]
                if face_id == hit_face_id:
                    continue
                similarity = face.get("similarity")
                try:
                    # db15查询  # 如有数据没有插进去 则会频繁报错int()
                    specific_data = self.redis_client.get_specific_data(hit_face_id)
                    single_face_data = {'face_image_id': str(hit_face_id), 'camera_id': specific_data.get("camera_id"),
                                        'similarity': similarity, 'face_image_uri': specific_data.get("face_image_uri"),
                                        'picture_uri': specific_data.get("picture_uri"),
                                        'timestamp': int(specific_data.get("timestamp")),
                                        'hezi_guidang_ip': specific_data.get("hezi_guidang_ip"),
                                        'ovn_f': specific_data.get("ovn_f")
                                        }

                    if single_face_data not in stranger_list:
                        stranger_list.append(single_face_data)

                except Exception as e:
                    continue
        return stranger_list

    # 档案库ovn
    def acvs_ovn(self, face_id, repo_id, face_b64):
        ovn_data = self.func_client_A.one_than_n_feature(
            feature=face_b64,
            threshold=self.threshold_f,
            repositories=repo_id,
            topk=self.stranger_limit
        ).get("message")

        # print("路人库 OVN:", ovn_data)
        # 档案ovn列表
        acvs_list = []
        for res in ovn_data.get("retrieval_results"):
            # 路人
            for face in res.get("similar_faces"):
                hit_face_id = json.loads(face.get("extra_meta"))["face_id"]
                if face_id == hit_face_id:
                    continue
                similarity = face.get("similarity")
                try:
                    # db15查询  # 如有数据没有插进去 则会频繁报错int()
                    specific_data = self.redis_client.get_specific_data(hit_face_id)
                    single_face_data = {'face_image_id': str(hit_face_id), 'camera_id': specific_data.get("camera_id"),
                                        'similarity': similarity, 'face_image_uri': specific_data.get("face_image_uri"),
                                        'picture_uri': specific_data.get("picture_uri"),
                                        'timestamp': int(specific_data.get("timestamp")),
                                        'hezi_guidang_ip': specific_data.get("hezi_guidang_ip"),
                                        'ovn_f': specific_data.get("ovn_f")
                                        }

                    if single_face_data not in acvs_list:
                        acvs_list.append(single_face_data)

                except Exception as e:
                    continue

        return acvs_list

    def change_static_repo(self, _id, feature, name, person_id, uri):
        # 查看id是否存在
        if self.redis_client.exists_id(_id) > 0:
            # id 存在调用put 更改盒子证件照 并升级redis 和 mongo
            face_img = self.redis_client.get_specific_data(_id)
            if face_img.get('camera_id') is not None:
                raise Exception("Face id in passer repo")

            hezi_guidang_face_id = int(face_img["hezi_guidang_face_id"])
            if feature is None:
                feature = face_img.get("ovn_f")

            if name is None:
                name = face_img.get("name")

            if person_id is None:
                person_id = face_img.get("person_id")

            if uri is None:
                uri = face_img.get("face_image_uri")

            # 升级盒子 PUT
            ins_result = self.func_client_J.insert_feature_put(face_img.get('hezi_guidang_repo_id'),
                                                               hezi_guidang_face_id, feature, _id, name=name,
                                                               person_id=person_id)
            if ins_result.get("message") != "success":
                raise Exception(ins_result.get("message"))

            # 升级resis 特征码 name person_id
            self.redis_client.insert_specific_data(_id, "ovn_f", feature)
            self.redis_client.insert_specific_data(_id, "name", name)
            self.redis_client.insert_specific_data(_id, "person_id", person_id)
            self.redis_client.insert_specific_data(_id, "face_image_uri", uri)

            # 升级mongo 特征码和 没存base64码
            self.m_client.updata_capture(_id, feature, name, person_id, uri)

            self.m_client.update_card_info(_id, uri, name, person_id)
            return True

        else:
            raise Exception("not exits card_id")

    # 上传静态库
    def saving_logic_static_repo(self, _id, name, person_id: str, uri, base64, feature=None):
        # 查看id是否存在
        if self.redis_client.exists_id(_id) > 0:
            # id 存在调用put 更改盒子证件照 并升级redis 和 mongo
            face_img = self.redis_client.get_specific_data(_id)
            if face_img.get('camera_id') is not None:
                raise Exception("Face id in passer repo")

            hezi_guidang_face_id = int(face_img["hezi_guidang_face_id"])

            if feature is None:
                feature = face_img.get("ovn_f")

            if name is None:
                name = face_img.get("name")

            if person_id is None:
                person_id = face_img.get("person_id")

            if uri is None:
                uri = face_img.get("face_image_uri")

            # 升级盒子 PUT
            ins_result = self.func_client_J.insert_feature_put(face_img.get('hezi_guidang_repo_id'),
                                                               hezi_guidang_face_id, feature, _id, name=name,
                                                               person_id=person_id)
            if ins_result.get("message") != "success":
                raise Exception(ins_result.get("message"))

            # 升级resis 特征码 name person_id
            self.redis_client.insert_specific_data(_id, "ovn_f", feature)
            self.redis_client.insert_specific_data(_id, "name", name)
            self.redis_client.insert_specific_data(_id, "person_id", person_id)
            self.redis_client.insert_specific_data(_id, "face_image_uri", uri)

            # 升级mongo 特征码和 没存base64码
            self.m_client.updata_capture(_id, feature, name, person_id, uri)

            self.m_client.update_card_info(_id, uri, name, person_id)
            return True

        hezi_face_id = self.m_client.get_hezi_face_id()
        # 获取人像库id
        card_repo_id, repo_id_key = self.m_client.get_current_use_repo('J')

        if feature is None:
            ins_result = self.func_client_J.insert_image(card_repo_id, hezi_face_id, base64, _id,
                                                         name, person_id)
        else:
            ins_result = self.func_client_J.insert_feature(card_repo_id, hezi_face_id,
                                                           feature, _id, name=name, person_id=person_id)
        if ins_result.get("message") != "success":
            data_dic = {
                "hezi_guidang_repo_id": card_repo_id,
                "face_id": _id,
                "hezi_guidang_face_id": hezi_face_id,
                "timestamp": 0,
                "hezi_guidang_ip": self.box_ip_J
            }
            self.m_client.insert_fail_img(data_dic)
            raise Exception(ins_result.get("message"))

        # 增值
        self.m_client.inc_count(repo_id_key, 'J')

        attributes_dic = {
            "_id": str(_id),
            "face_image_id": str(_id),
            "hezi_guidang_ip": self.box_ip_J,
            "name": str(name),
            "person_id": person_id,
            "hezi_guidang_repo_id": str(card_repo_id),
            "face_image_uri": str(uri),
            "picture_uri": str(uri),
            "timestamp": 0,
            "hezi_guidang_face_id": hezi_face_id,
            "ovn_f": feature if feature else self.get_face_feature(fun_client=self.func_client_J, repo_id=card_repo_id,
                                                                   hezi_face_id=hezi_face_id)
        }
        # 数据插入mongo
        self.m_client.ins_capture(attributes_dic)
        # 数据插入redis db15
        for key, value in attributes_dic.items():
            self.redis_client.insert_specific_data(_id, key, str(value))
        return True
